梦入琼楼寒有月,行过石树冻无烟

Vue.js component

组件(component) 是 Vue.js 中最为核心的功能,在前端应用程序中可以采用模块化以及实现可重用、可扩展的 Vue 实例,通常使用 template 作为方法进行注册组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id="app">
<button-counter></button-counter>
</div>
<script>
const app = Vue.createApp({})
app.component('button-counter', {
data() {
return {
count: 0
}
},
template: `
<button @click="count++">
This is click {{count}}
</button>
`
}).mount('#app')
</script>

当然我们也可以重复使用各个独立的 <button-counter> 组件,但前提我们的组件需要高度解藕。

点击按钮的时候,上述的 flag 将会被证实,就因为每个组件都会各自独立并维护他的 count,每次使用 <button-conters> 都会有一个新的实例会被新建。

1
2
3
4
5
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>


或者可以选择组件使用同一个 count 来进行同时的数据绑定与渲染:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script>
const app = Vue.createApp({})
var buttonCounter = {
count: 0
}
app.component('button-counter', {
data() {
return buttonCounter
},
template: `
<button @click="count++">
This is click {{count}}
</button>
`
}).mount('#app')
</script>

Prop

Prop 也被直译为 “支柱”,通常他可以为组建提供一个属性用于传递数据并建立链接,这也方便了数据的获取和各个组件之间的解藕:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<style>
.header {
border: 1px solid #eaeaea;
padding: 2em;
width: 40%;
}
.header_item {
border-left: 10px solid #1488ff;
padding-left: 14px;
}
.header_txt {
text-indent: 1em;
}
</style>
<div id="app">
<item-main title="Hey,world" text="当然我们也可以重复使用各个独立的 <button-counter> 组件,但前提我们的组件需要高度解藕。点击按钮的时候,上述的 flag 将会被证实,就因为每个组件都会各自独立并维护他的 count,每次使用 <button-conters> 都会有一个新的实例会被新建。"></item-main>
</div>
<script>
const app = Vue.createApp({})
app.component('item-main', {
data() {
return {
}
},
props: ['title', 'text'],

template: `
<div class="header">
<h1 class="header_item">{{title}}</h1>
<p class="header_txt">{{text}}</p>
</div>
`
}).mount('#app')
</script>

为了使用的方便我们还可以直接使用 Prop 数组来提供数据的绑定和输出,这会更加的方便和简洁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<style>
.header {
border: 1px solid #eaeaea;
padding: 2em;
width: 40%;
}
.header_item {
border-left: 10px solid #1488ff;
padding-left: 14px;
}
.header_txt {
text-indent: 1em;
}
</style>
<div id="app">
<item-main
v-for="post in posts"
:key="post.id"
:title="post.title"
:txt="post.txt"
></item-main>
</div>
<script>
const App = {
data() {
return {
posts: [
{ id: 1, title: 'Vue', txt: '一个优秀的渐进式框架'},
{ id: 2, title: 'Jquery', txt: 'JavaScript 组件库,集成了多种实用方法'},
{ id: 3, title: 'D3', txt: '专业的数据可视化框架'}
]
}
}
}
const app = Vue.createApp(App)

app.component('item-main', {
props: ['title', 'txt'],
template: `
<div class="header">
<h1 class="header_item">{{title}}</h1>
<p class="header_txt">{{txt}}</p>
</div>
`
})

app.mount('#app')
</script>

监听


最为明显的一个例子就是通过监听器来修改字号或进行一些其他方面的监听,而这这种的实现方式也非常的简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<style>
.header {
border: 1px solid #eaeaea;
padding: 2em;
width: 40%;
}
.header_item {
border-left: 10px solid #1488ff;
padding-left: 14px;
}
.header_txt {
text-indent: 1em;
}
.txt_button {
float: left;
display: -webkit-inline-box;
}
</style>
<div id="app">
<item-main title="Hey,world" text="当然我们也可以重复使用各个独立的 <button-counter> 组件,但前提我们的组件需要高度解藕。点击按钮的时候,上述的 flag 将会被证实,就因为每个组件都会各自独立并维护他的 count,每次使用 <button-conters> 都会有一个新的实例会被新建。"></item-main>
<div class="txt_button">
<button-addcounter></button-addcounter>
<button-redcounter></button-redcounter>
</div>
</div>
<script>
const app = Vue.createApp({})
var txtSize = {
size: '15'
}
app.component('item-main', {
data() {
return txtSize
},
props: ['title', 'text'],
template: `
<div class="header">
<h1 class="header_item">{{title}}</h1>
<p class="header_txt" :style="{fontSize: size+'px'}">{{text}}</p>
</div>
`
})
app.component('button-redcounter', {
data() {
return txtSize;
},
template: `
<button @click="size--">
Reduce to fontSize - 1
</button>
`
})
app.component('button-addcounter', {
data() {
return txtSize;
},
template: `
<button @click="size++">
Add to fontSize + 1
</button>
`
})
app.mount('#app')
</script>

插槽


组件通常通过元素进行使用,并以属性作为内容,而元素本身的内容将会被覆盖,因此 Vue 提供了 <slot> 元素来解决这一问题,此外 slot 也可被理解为组件之间的一种传递方式或占位符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<style>
.header {
border: 1px solid #eaeaea;
padding: 2em;
width: 40%;
}
.header_item {
border-left: 10px solid #1488ff;
padding-left: 14px;
}
.header_txt {
text-indent: 1em;
}
</style>
<div id="app">
<item-main>和 HTML 元素一样,我们经常需要向一个组件传递内容</item-main>
</div>
<script>
const app = Vue.createApp({})
app.component('item-main', {
data() {
return {
title: 'This is <slot>'
}
},
template: `
<div class="header">
<h1 class="header_item">{{title}}</h1>
<slot></slot>
</div>
`
}).mount('#app')
</script>

动态组件

在通常情况下,不同组件之间的动态切换可以让页面变得更加的拥有趣味,且可以减少一些不必要的从页面占用。动态组建可以用于构建一些非动态的填写,而如果需要满足一些OAuth等切换或登录的场景,则需要使用 Vue 动态组件中的异步组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<div id="app">
<button
v-for="nav in navs"
:key="nav"
@click="currentTab = nav">{{nav}}</button>
<component :is="currentTabDev"></component>
</div>
<script>
const app = Vue.createApp({
data() {
return {
currentTab: 'Home',
navs: ['home', 'arch', 'about']
}
},
computed: {
currentTabDev() {
return 'nav-' + this.currentTab.toLowerCase()
}
}
})

app.component('nav-home', {
template: `
<div>Home</div>
`
})
app.component('nav-arch', {
template: `
<div>Arch</div>
`
})
app.component('nav-about', {
template: `
<div>About</div>
`
})
app.mount('#app')
</script>

上述 code 中,currentTabDev 可以是一个组件的名字或一个选项对象,通过 :is 属性来作为一个自定义的内置元素进行转译。

很多时候我们所使用的 :key 只是用于进行排序,有相同父元素的子元素必须有唯一的 key。重复的 key 会造成渲染错误,因此需要使用属性

也就是说当 currentTabDev 发生改变的时候,组件也就会发生变化,这是 Vue 3.x 中所新增的特殊属性。

keep-alive

Vue创建一个新的 ```currentTabDev``` 实例,也就是说只要通过使用``````元素进行包裹,即可让他们在第一次创建时会被进行**缓存**,即保存刚刚切换后的数据,为了更加的体现```< keep-alive>```效果,我们可以使用表单来进行验证:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

![未使用 keep-alive](https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/20210924014746.gif)


![使用 keep-alive](https://49812933408852955071488026628034-1301075051.cos.ap-nanjing.myqcloud.com/20210924014955.gif)


```js
<div id="app">
<button
v-for="nav in navs"
:key="nav"
@click="currentTab = nav">{{nav}}</button>
<keep-alive>
<component :is="currentTabDev"></component>
</keep-alive>
</div>
<script>
const app = Vue.createApp({
data() {
return {
currentTab: 'Home',
navs: ['home', 'arch', 'about']
}
},
computed: {
currentTabDev() {
return 'nav-' + this.currentTab.toLowerCase()
}
}
})

app.component('nav-home', {
template: `
<div><input type="text" /></div>
`
})
app.component('nav-arch', {
template: `
<div>Arch</div>
`
})
app.component('nav-about', {
template: `
<div>About</div>
`
})
app.mount('#app')
</script>
⬅️ Go back